import { createConnection, createServer, ListenOptions, Server, Socket, TcpNetConnectOpts} from "net";
import { ConnectionOptions } from "tls";
import TiggerTcpClient from "../client/client";
import { control_log, dispatcher_err, dispatcher_log } from "../log/logger";
import ClientController from "../clientcontroller/ClientController";
import PacketPatcher from "../packethandler/PacketPatcher";
import Channel from "../channel/channel";
import readline = require("readline");

interface client {
    client: Socket,
    referPort: number;
    connectPort: number;
    isInitConnection: boolean;
}
interface inbounds {
    [index: string]: client;
}
export default class DispatchInbound
{
    private client: TiggerTcpClient;    //控制通道（客户端）

    private options: ListenOptions; //本地服务器监听选项
    private local_server: Server;   //本地服务器

    private tunnelN: number;    //通道数
    private channel: Channel;   //多通道控制器

    private allow_tunnel_connect: boolean;  //通道是否允许传输数据
    private pause_socket_queue: Socket[];

    //private inboundController: ClientController; //连入本地服务器的客户端控制器
    private inbounds: inbounds[];
    private counter: number;

    constructor(options: ListenOptions, client: TiggerTcpClient, tunnelN: number) {
        this.counter = 0;
        this.options = options;
        this.client = client;
        this.tunnelN = tunnelN;
        this.allow_tunnel_connect = false;
        //this.inboundController = new ClientController();
        this.inbounds = new Array<inbounds>();
        this.pause_socket_queue = new Array<Socket>();

        //this.openPerformenceCounter();
        this.client
          .registerControlCommand("server_port_close", (args: number[]) => {
            let client:client = this.inbounds[args[0].toString()];
            client.client.destroy();

            this.inbounds[args[0].toString()] = undefined;
        }).registerControlCommand("tunnel_ok", (args: number[]) => {
            //连接远程隧道
            let client_connection_options:ConnectionOptions = {
                port: args[0],
                host: this.client.getRemoteHost()
            }

            this.channel = new Channel(tunnelN, false, false, client_connection_options);

            this.channel.regChannelAllConnected(() => {
                this.allow_tunnel_connect = true;
                console.log('多通道连接完成');
            });

            this.channel.regDataRecive((refPort: number, data: Buffer) => {
                if(this.inbounds[refPort.toString()] != undefined) 
                {
                    if(!this.inbounds[refPort.toString()].client.write(data))
                    {
                        console.log("写入错误");
                        this.channel.pause();
                    }
                }
            });
            this.channel.regChannelDrain(() => {

                //for(let i in this.inbounds)
                //{
                    //let client:any = this.inbounds[i];
                    //if(client != undefined && client.isInitConnection == false)
                    //{
                        //client.client.resume();
                    //}
                //}

            });
        }).registerControlCommand("server_port_open", (args: number[]) => {
            this.inbounds[args[0].toString()].client.resume();
            //设定client已经初始化
            this.inbounds[args[0].toString()].client.isInitConnection = false;
        }).startControledByServer();



        //监听端口
        this.local_server = createServer();
        this.local_server.listen(options, () => {
            dispatcher_log("监听" + this.options.port + "端口");
        });

        this.local_server.on("connection", (socket: Socket) => {
            
            //默认连进的客户端是暂停数据传输的,必须等待控制通道connl传回确认服务器已经连接目标服务器才可以传输
            socket.pause();

            let newClient:client = {
                client: socket,
                referPort: socket.remotePort,
                connectPort: 0,
                isInitConnection: true
            };

            if(this.inbounds[newClient.referPort.toString()] != undefined)
            {
                dispatcher_log("连接池中出现未曾释放的端口" + this.inbounds[newClient.referPort.toString()]);
            }

            if(!this.channel.isChannelDrain())
            {
                //newClient.client.pause();
            }
            this.inbounds[newClient.referPort.toString()] = newClient;

            this.client.pushControlData("client_port_open", [newClient.referPort]);

            socket.on("data", (data:Buffer) => {
                //this.setClientData(client_id, data);
                //client.data = Buffer.concat([client.data, data]);

                if(this.allow_tunnel_connect)
                {
                    //通道开通才允许转发
                    if(!this.channel.sendData(data, newClient.referPort))
                    {
                        return;

                        if(!this.channel.isChannelDrain())
                        {
                            for(let i in this.inbounds)
                            {
                                let client:any = this.inbounds[i];
                                if(client != undefined && client.isInitConnection == false)
                                {
                                    client.client.pause();
                                }
                            }
                        }
                    }
                        // console.log("暂停应用程序>>>客户端的通道");
                        // socket.pause();
                        // this.pause_socket_queue.push(socket);
                    
                }

                // this.pushClientBufferToPushPool();
                // this.pushDataToServer();
            });

            socket.on("drain", () => {
                console.log("恢复服务器>>>客户端的多线程通道");
                this.channel.resume();
            });

            socket.on("close", (has_error:boolean) => {
                this.client.pushControlData("client_port_close", [newClient.referPort]);

            })
            socket.on("error", (err) => {});
        });
        
        //请求服务器开通指定通道
        this.client.registerWiredCallback(() => {
            this.client.pushControlData("tunnel_open", [this.tunnelN]);
        });
    }

    private openPerformenceCounter() {
        setInterval(() => {

            readline.cursorTo(process.stdout, 0, 0, () => {
                readline.clearLine(process.stdout, 0, () => {
                    //console.log(this.channel.getStopTunnels());
                    return;
                    let res: string[] = [];
                    for(let i in this.inbounds)
                    {
                        if(this.inbounds[i] != undefined)
                            res.push(i);
                    }
                    
                    console.log(res);
                })
            });
        }, 500);
    }
}